package cn.sanli.manage.service.impl;

import cn.sanli.manage.ex.ServiceException;
import cn.sanli.manage.mapper.data1.CorresMapper;
import cn.sanli.manage.mapper.data1.FaultAssessMapper;
import cn.sanli.manage.mapper.data1.FaultMapper;
import cn.sanli.manage.mapper.data1.UserInfoMapper;
import cn.sanli.manage.pojo.dto.Fault.*;
import cn.sanli.manage.pojo.entity.Corres;
import cn.sanli.manage.pojo.entity.Fault;
import cn.sanli.manage.pojo.vo.Fault.*;
import cn.sanli.manage.security.LoginPrincipal;
import cn.sanli.manage.service.FaultService;
import cn.sanli.manage.service.WechatService;
import cn.sanli.manage.utils.DateUtils;
import cn.sanli.manage.web.ServiceCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;

/**
 * 过错信息表(Fault)表服务实现类
 *
 * @author wzy
 * @since 2023-12-07 16:58:18
 */
@Service("faultService")
@Slf4j
public class FaultServiceImpl implements FaultService {

    @Resource // 过错信息表Mapper层
    private FaultMapper faultMapper;

    @Resource // 过错关联表Mapper层
    private FaultAssessMapper faultAssessMapper;

    @Resource // 字段映射表Mapper层
    private CorresMapper corresMapper;

    @Resource // 微信推送Mapper层
    private WechatService wechatService;

    @Resource // 用户信息Mapper层
    UserInfoMapper userInfoMapper;


    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public Fault queryById(Integer id) {
        return faultMapper.queryById(id);
    }

    /**
     * 根据条件分页查询
     *
     * @param queryRequest 查询条件
     * @return 符合条件的数据
     */
    @Override
    public List<FaultPagingQueryVO> pagingQuery(PageQueryOfFaultRequest queryRequest) {
        // 根据条件从数据库获取符合条件的数据
        List<FaultPagingQueryVO> faultAndFaultAssessInfos = faultMapper.pagingQuery(queryRequest);
        log.debug("根据条件查询到的数据: {}", faultAndFaultAssessInfos);
        // 从字段映射表中获取所有信息
        List<Corres> corresList = corresMapper.selectAll();
        Map<Integer, String> map = new HashMap<>();
        // 字段映射集合, 以id为key, name为value存入map
        for (Corres corres : corresList) {
            map.put(corres.getId(), corres.getName());
        }
        for (FaultPagingQueryVO faultPagingQueryVO : faultAndFaultAssessInfos) {
            faultPagingQueryVO.setFaultType(map.get(faultPagingQueryVO.getFaultTypeId()));
            faultPagingQueryVO.setFaultLevel(map.get(faultPagingQueryVO.getFaultLevelId()));
            faultPagingQueryVO.setFaultDisposalForm(map.get(faultPagingQueryVO.getFaultDisposalFormId()));
            faultPagingQueryVO.setOtherResults(map.get(faultPagingQueryVO.getOtherResultsId()));
            faultPagingQueryVO.setOtherDisposal(map.get(faultPagingQueryVO.getOtherDisposalId()));
            faultPagingQueryVO.setDisposalLevel(map.get(faultPagingQueryVO.getDisposalLevelId()));
            faultPagingQueryVO.setApprovalType(map.get(faultPagingQueryVO.getApprovalTypeId()));
            faultPagingQueryVO.setFaultAssessDisposalForm(map.get(faultPagingQueryVO.getFaultAssessDisposalFormId()));
        }

        return faultAndFaultAssessInfos;
    }

    /**
     * 考核信息积分统计
     *
     * @return 结果集
     */
    @Override
    public List<FaultStatisticsInfoVO> statisticsFaultOfPersonage(LoginPrincipal loginPrincipal) {
        int roleId = loginPrincipal.getRoleId();
        log.debug("识别到的当事人: {}  主显权限: {}", loginPrincipal, roleId);
        // 分别获取本周,本月,本季,半年,本年的时间段
        Map<String, Date[]> statisticsTime = DateUtils.getStatisticsTime();

        // 声明一个请求参数封装类, 根据权限大小给查询条件实体类属性赋值
        FaultInfoStatisticsRequest statisticsRequest = new FaultInfoStatisticsRequest();
        statisticsRequest.setStartTime(statisticsTime.get(DateUtils.THISYEAR)[0]);
        statisticsRequest.setEndTime(statisticsTime.get(DateUtils.THISYEAR)[1]);
        if(roleId == 1 || roleId == 2 || roleId==3 || roleId == 7) {

        } else if (roleId == 4) {
            statisticsRequest.setResCenter(loginPrincipal.centerId);
        } else if (roleId == 5 || roleId == 6){
            statisticsRequest.setResDept(loginPrincipal.getDeptId());
        }else {
//            statisticsRequest.setResNum(Integer.valueOf(loginPrincipal.getNum()));
            statisticsRequest.setResNum(Integer.valueOf("16766"));
        }

        // 根据查询条件搜索数据库
        List<FaultStatisticsVO> faultStatisticsOfPersonageVOs
                = faultMapper.statisticsFaultOfPersonage(statisticsRequest);
        log.debug("根据条件获取到{}条数据", faultStatisticsOfPersonageVOs.size());
        log.debug("根据条件获取到的数据: {}", faultStatisticsOfPersonageVOs);

        // 以工号为key(), 当前对象为value存入map
        Map<String, List<FaultStatisticsVO>> map = new HashMap<>();
        List<FaultStatisticsVO> listOfMap = new ArrayList<>();
        for (FaultStatisticsVO statisticsVO : faultStatisticsOfPersonageVOs) {
            if(map.containsKey(statisticsVO.getResNum())) {
                listOfMap = map.get(statisticsVO.getResNum());
                listOfMap.add(statisticsVO);
                map.put(statisticsVO.getResNum(), listOfMap);
            }else {
                List<FaultStatisticsVO> list = new ArrayList<>();
                list.add(statisticsVO);
                map.put(statisticsVO.getResNum(), list);
            }
        }

        // 创建List集合用于接受最终数据并返回
        List<FaultStatisticsInfoVO> list = new ArrayList<>();
        // 遍历map集合, 调用数据统计方法
        for (String key : map.keySet()) {
            FaultStatisticsInfoVO statisticsInfo = this.getStatisticsInfo(map.get(key), statisticsTime);
            log.debug("从map中获取key为{}的数据: {}", key, statisticsInfo);
            list.add(statisticsInfo);
        }
        log.debug("将统计完的数据集合返回: {}", list);

        // 返回
        return list;
    }


    /**
     * 部门积分统计
     * @param loginPrincipal 当事人
     * @return 经过处理的结果集
     */
    public List<FaultStatisticsInfoOfDeptVO> statisticsFaultOfDept(LoginPrincipal loginPrincipal){
        int roleId = loginPrincipal.getRoleId();
        log.debug("识别到的当事人: {}  主显权限: {}", loginPrincipal, roleId);
        // 分别获取本周,本月,本季,半年,本年的时间段
        Map<String, Date[]> statisticsTime = DateUtils.getStatisticsTime();

        // 声明一个请求参数封装类, 根据权限大小给查询条件实体类属性赋值
        FaultInfoStatisticsRequest statisticsRequest = new FaultInfoStatisticsRequest();
        statisticsRequest.setStartTime(statisticsTime.get(DateUtils.THISYEAR)[0]);
        statisticsRequest.setEndTime(statisticsTime.get(DateUtils.THISYEAR)[1]);
        if(roleId == 1 || roleId == 2 || roleId==3 || roleId == 7) {

        } else if (roleId == 4) {
            statisticsRequest.setResCenter(loginPrincipal.centerId);
        }

        // 根据查询条件搜索数据库
        List<FaultStatisticsVO> faultStatisticsOfPersonageVOs
                = faultMapper.statisticsFaultOfPersonage(statisticsRequest);
        log.debug("根据条件获取到{}条数据", faultStatisticsOfPersonageVOs.size());
        log.debug("根据条件获取到的数据: {}", faultStatisticsOfPersonageVOs);

        // 以部门id为key(), 当前对象为value存入map
        Map<String, List<FaultStatisticsVO>> map = new HashMap<>();
        List<FaultStatisticsVO> listOfMap = new ArrayList<>();
        for (FaultStatisticsVO statisticsVO : faultStatisticsOfPersonageVOs) {
            if(map.containsKey(statisticsVO.getResDept())) {
                listOfMap = map.get(statisticsVO.getResDept());
                listOfMap.add(statisticsVO);
                map.put(statisticsVO.getResDept(), listOfMap);
            }else {
                List<FaultStatisticsVO> list = new ArrayList<>();
                list.add(statisticsVO);
                map.put(statisticsVO.getResDept(), list);
            }
        }

        // 创建List集合用于接受最终数据并返回
        List<FaultStatisticsInfoOfDeptVO> list = new ArrayList<>();
        // 遍历map集合, 调用数据统计方法
        for (String key : map.keySet()) {
            FaultStatisticsInfoVO statisticsInfo = this.getStatisticsInfo(map.get(key), statisticsTime);
            log.debug("从map中获取key为{}的数据: {}", key, statisticsInfo);
            FaultStatisticsInfoOfDeptVO deptVO = new FaultStatisticsInfoOfDeptVO();
            BeanUtils.copyProperties(statisticsInfo, deptVO);
            list.add(deptVO);
        }
        log.debug("将统计完的数据集合返回: {}", list);

        // 返回
        return list;
    }


    /**
     * 大口积分统计
     * @param loginPrincipal 当事人
     * @return 经过处理的结果集
     */
    public List<FaultStatisticsInfoOfCenterVO> statisticsFaultOfCenter(LoginPrincipal loginPrincipal){
        int roleId = loginPrincipal.getRoleId();
        log.debug("识别到的当事人: {}  主显权限: {}", loginPrincipal, roleId);
        // 分别获取本周,本月,本季,半年,本年的时间段
        Map<String, Date[]> statisticsTime = DateUtils.getStatisticsTime();

        // 声明一个请求参数封装类, 根据权限大小给查询条件实体类属性赋值
        FaultInfoStatisticsRequest statisticsRequest = new FaultInfoStatisticsRequest();
        statisticsRequest.setStartTime(statisticsTime.get(DateUtils.THISYEAR)[0]);
        statisticsRequest.setEndTime(statisticsTime.get(DateUtils.THISYEAR)[1]);
//        if(roleId == 1 || roleId == 2 || roleId==3 || roleId == 7) {
//
//        } else if (roleId == 4) {
//            statisticsRequest.setResCenter(loginPrincipal.centerId);
//        }

        // 根据查询条件搜索数据库
        List<FaultStatisticsVO> faultStatisticsOfPersonageVOs
                = faultMapper.statisticsFaultOfPersonage(statisticsRequest);
        log.debug("根据条件获取到{}条数据", faultStatisticsOfPersonageVOs.size());
        log.debug("根据条件获取到的数据: {}", faultStatisticsOfPersonageVOs);

        // 以大口id为key(), 当前对象为value存入map
        Map<String, List<FaultStatisticsVO>> map = new HashMap<>();
        List<FaultStatisticsVO> listOfMap = new ArrayList<>();
        for (FaultStatisticsVO statisticsVO : faultStatisticsOfPersonageVOs) {
            if(map.containsKey(statisticsVO.getResCenter())) {
                listOfMap = map.get(statisticsVO.getResCenter());
                listOfMap.add(statisticsVO);
                map.put(statisticsVO.getResCenter(), listOfMap);
            }else {
                List<FaultStatisticsVO> list = new ArrayList<>();
                list.add(statisticsVO);
                map.put(statisticsVO.getResCenter(), list);
            }
        }

        // 创建List集合用于接受最终数据并返回
        List<FaultStatisticsInfoOfCenterVO> list = new ArrayList<>();
        // 遍历map集合, 调用数据统计方法
        for (String key : map.keySet()) {
            FaultStatisticsInfoVO statisticsInfo = this.getStatisticsInfo(map.get(key), statisticsTime);
            log.debug("从map中获取key为{}的数据: {}", key, statisticsInfo);
            FaultStatisticsInfoOfCenterVO centerVO = new FaultStatisticsInfoOfCenterVO();
            BeanUtils.copyProperties(statisticsInfo, centerVO);
            list.add(centerVO);
        }
        log.debug("将统计完的数据集合返回: {}", list);

        // 返回
        return list;
    }


    private FaultStatisticsInfoVO getStatisticsInfo(List<FaultStatisticsVO> list, Map<String, Date[]> statisticsTime) {
        log.debug("调用getStatisticsInfo统计数据, 需处理的数据: {}  时间参数: {}", list, statisticsTime);
        FaultStatisticsInfoVO personageVO = new FaultStatisticsInfoVO();
        // 声明并初始化五个变量后续使用
        BigDecimal ofWeek = new BigDecimal("0.0");
        BigDecimal ofMonth = new BigDecimal("0.0");
        BigDecimal ofQuarter = new BigDecimal("0.0");
        BigDecimal ofHalf = new BigDecimal("0.0");
        BigDecimal ofYear = new BigDecimal("0.0");
        // 遍历数据集合
        for (FaultStatisticsVO statisticsOfPersonageVO : list) {
            log.debug("本次循环的数据: {}", statisticsOfPersonageVO);
            // 根据考核时间判断
            if(statisticsOfPersonageVO.getFaultTime().getTime() >= statisticsTime.get(DateUtils.THISWEEK)[0].getTime()
                            &&
                statisticsOfPersonageVO.getFaultTime().getTime() <= statisticsTime.get(DateUtils.THISWEEK)[1].getTime()) {
                ofWeek = ofWeek.add(statisticsOfPersonageVO.getDisposalDetails());
                ofMonth = ofMonth.add(statisticsOfPersonageVO.getDisposalDetails());
                ofQuarter = ofQuarter.add(statisticsOfPersonageVO.getDisposalDetails());
                ofHalf = ofHalf.add(statisticsOfPersonageVO.getDisposalDetails());
                ofYear = ofYear.add(statisticsOfPersonageVO.getDisposalDetails());
                continue;
            }else if(statisticsOfPersonageVO.getFaultTime().getTime() >= statisticsTime.get(DateUtils.THISMONTH)[0].getTime()
                            &&
                    statisticsOfPersonageVO.getFaultTime().getTime() <= statisticsTime.get(DateUtils.THISMONTH)[1].getTime()) {
                ofMonth = ofMonth.add(statisticsOfPersonageVO.getDisposalDetails());
                ofQuarter = ofQuarter.add(statisticsOfPersonageVO.getDisposalDetails());
                ofHalf = ofHalf.add(statisticsOfPersonageVO.getDisposalDetails());
                ofYear = ofYear.add(statisticsOfPersonageVO.getDisposalDetails());
                continue;
            }else if(statisticsOfPersonageVO.getFaultTime().getTime() >= statisticsTime.get(DateUtils.THISQUARTER)[0].getTime()
                    &&
                    statisticsOfPersonageVO.getFaultTime().getTime() <= statisticsTime.get(DateUtils.THISQUARTER)[1].getTime()) {
                ofQuarter = ofQuarter.add(statisticsOfPersonageVO.getDisposalDetails());
                ofHalf = ofHalf.add(statisticsOfPersonageVO.getDisposalDetails());
                ofYear = ofYear.add(statisticsOfPersonageVO.getDisposalDetails());
                continue;
            }else if(statisticsOfPersonageVO.getFaultTime().getTime() >= statisticsTime.get(DateUtils.THISHALF)[0].getTime()
                    &&
                    statisticsOfPersonageVO.getFaultTime().getTime() <= statisticsTime.get(DateUtils.THISHALF)[1].getTime()) {
                ofHalf = ofHalf.add(statisticsOfPersonageVO.getDisposalDetails());
                ofYear = ofYear.add(statisticsOfPersonageVO.getDisposalDetails());
                continue;
            }else if(statisticsOfPersonageVO.getFaultTime().getTime() >= statisticsTime.get(DateUtils.THISYEAR)[0].getTime()
                    &&
                    statisticsOfPersonageVO.getFaultTime().getTime() <= statisticsTime.get(DateUtils.THISYEAR)[1].getTime()) {
                ofYear = ofYear.add(statisticsOfPersonageVO.getDisposalDetails());
                continue;
            }
        }
        // 基本信息属性赋值
        personageVO.setResName(list.get(0).getResName());
        personageVO.setResNum(list.get(0).getResNum());
        personageVO.setResDept(list.get(0).getResDept());
        personageVO.setResCenter(list.get(0).getResCenter());
        // 积分信息赋值, 四舍五入保留一位小数
        personageVO.setStatisticsOfWeek(ofWeek.setScale(1, RoundingMode.HALF_UP));
        personageVO.setStatisticsOfMonth(ofMonth.setScale(1, RoundingMode.HALF_UP));
        personageVO.setStatisticsOfQuarter(ofQuarter.setScale(1, RoundingMode.HALF_UP));
        personageVO.setStatisticsOfHalf(ofHalf.setScale(1, RoundingMode.HALF_UP));
        personageVO.setStatisticsOfYear(ofYear.setScale(1, RoundingMode.HALF_UP));

        return personageVO;
    }


    /**
     * 新增数据
     *
     * @param faultInsertRequest 实例对象
     * @return 实例对象
     */
    @Override
    @Transactional
    public boolean insert(FaultInsertRequest faultInsertRequest, LoginPrincipal loginPrincipal) {
        log.debug("service层接收到的参数: {}", faultInsertRequest);
        log.debug("获取到的当事人类型数据:{}", loginPrincipal);
        FaultDTO faultDTO = new FaultDTO();
        BeanUtils.copyProperties(faultInsertRequest, faultDTO);
        log.debug("同名属性赋值后L{}", faultDTO.toString());
        log.debug("开始处理新增过错信息业务逻辑, 参数: {}", faultDTO);

        // 获取最近的一个过错编号, 并往后延续赋值
        String maxFaultNum = faultMapper.getMaxFaultNum();
        if(maxFaultNum == null) {
            throw new ServiceException(ServiceCode.ERROR_INSERT, "数据库有误, 新增失败");
        }
        String substring = maxFaultNum.substring(1);
        log.debug("截取到的rid数值部分: {}", substring);
        faultDTO.setFaultNum("G" + (Integer.parseInt(substring) + 1));


        String corresName = corresMapper.selectByPrimaryKey(faultDTO.getFaultAssessDisposalForm()).getName();
        faultDTO.setDisposalResults(corresName + ":" + faultDTO.getDisposalDetails());
        faultDTO.setAssessResults(faultDTO.getDisposalResults() + "/" + faultDTO.getAssessNum());
        faultDTO.setFaultLevelOfNum(faultInsertRequest.getFaultLevel());
        faultDTO.setCreatName(loginPrincipal.getUserName());
        // 向过错信息表新增数据
        log.debug("补充完参数属性后: {}", faultDTO);
        int insert = faultMapper.insert(faultDTO);
        Integer id = faultDTO.getId();
        if(insert <= 0) {
            throw new ServiceException(ServiceCode.ERROR_INSERT, "过错信息新增数据失败");
        }
        log.debug("开始向过错关联表中新增关联信息, 参数: {}", faultInsertRequest);
        int row = faultAssessMapper.insert(faultDTO);
        if(row <= 0) {
            throw new ServiceException(ServiceCode.ERROR_INSERT, "新增过错关联信息失败");
        }

        // 获取时间段
        Map<String, Date[]> statisticsTime = DateUtils.getStatisticsTime();
        // 根据工号搜索用户的计分标准
        FaultStandardVO faultStandardVO = userInfoMapper.selectStandardByNumber(faultInsertRequest.getResNum());
        // 根据工号搜索员工所有计分信息
        List<FaultStatisticsVO> statisticsVOS = faultMapper.queryByNumber(faultInsertRequest.getResNum());
        // 对用户计分数据进行整理
        FaultStatisticsInfoVO statisticsInfo = this.getStatisticsInfo(statisticsVOS, statisticsTime);

        // 获取字段名
        FaultInfo faultInfo = faultMapper.queryFaultInfoById(id);

        log.debug("向{}推送消息", faultStandardVO.getWeChat());
        // 像这个倒霉蛋推送考核消息消息
        wechatService.sendMessage(faultStandardVO.getWeChat(), "尊敬的" + faultInfo.getResName() + "(工号:" + faultInfo.getResNum() + "), 您好 " + "\r\n" +
                                                                        "您在" + DateUtils.date(faultInfo.getFaultTime()) + "因" + faultInfo.getFaultType() + "发生" + faultInfo.getFaultLevel() + "过错, " +
                                                                        "具体事实:" + faultInfo.getFaultContent()+ ", 处理部门:" + faultInfo.getDisposalDept() + ", 处理人:" + faultInfo.getDisposalName() +
                                                                        ", 处理结果:" + faultInfo.getDisposalResults() + "分\r\n" +
                                                                        "[统计]:" + "\r\n" +
                                                                        "本周计分:" + statisticsInfo.getStatisticsOfWeek() + ", 本月计分:" + statisticsInfo.getStatisticsOfMonth() +
                                                                        ", 本季度计分:" + statisticsInfo.getStatisticsOfQuarter() + ", 本半年计分:" + statisticsInfo.getStatisticsOfHalf() +
                                                                        ", 本年度计分:" + statisticsInfo.getStatisticsOfYear() + "\r\n" +
                                                                        "请您前往记分奖惩管理软件进行查看，如有异议请及时与相关部门沟通！");

        return true;
    }


    /**
     * 修改数据
     *
     * @param faultUpdateRequest 实例对象
     * @return 实例对象
     */
    @Override
    @Transactional
    public boolean update(FaultUpdateRequest faultUpdateRequest, LoginPrincipal loginPrincipal) {
        log.debug("service层接收到的参数: {}", faultUpdateRequest);
        FaultDTO faultDTO = new FaultDTO();
        BeanUtils.copyProperties(faultUpdateRequest, faultDTO);

        String corresName = corresMapper.selectByPrimaryKey(faultDTO.getFaultAssessDisposalForm()).getName();
        faultDTO.setDisposalResults(corresName
                + ":" + faultDTO.getDisposalDetails());
        faultDTO.setAssessResults(faultDTO.getDisposalResults() + "/" +
                faultDTO.getAssessNum());
        faultDTO.setFaultLevelOfNum(faultUpdateRequest.getFaultLevel());
        faultDTO.setCreatName(loginPrincipal.getUserName());
        faultDTO.setFaultLevelOfNum(faultUpdateRequest.getFaultLevel());
        log.debug("开始处理修改过错信息业务逻辑, 参数: {}", faultDTO);
        // 向过错信息表新增数据
        int updateFault = faultMapper.update(faultDTO);
        if(updateFault <= 0) {
            throw new ServiceException(ServiceCode.ERROR_UPDATE, "向过错信息表(Fault)修改数据失败");
        }
        log.debug("开始向过错关联表中修改关联信息, 参数: {}", faultUpdateRequest);
        int updateFaultAssess = faultAssessMapper.update(faultDTO);
        if(updateFaultAssess <= 0) {
            throw new ServiceException(ServiceCode.ERROR_UPDATE, "向过错关联表(FaultAssess)修改数据失败");
        }
        return true;
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    @Transactional
    public boolean deleteById(Integer id) {
        int row1 = faultMapper.deleteById(id);
        log.debug("删除过错信息完毕, 受影响行数:{}", row1);
        if(row1 <=0) {
            throw new ServiceException(ServiceCode.ERROR_DELETE, "删除过错信息失败");
        }
        int row2 = faultAssessMapper.deleteById(id);
        log.debug("删除过错关联信息完毕, 受影响行数: {}", row2);
        if(row2 <= 0) {
            throw new ServiceException(ServiceCode.ERROR_DELETE, "删除过错关联信息失败");
        }
        return  true;
    }
}
